package cn.edu.ctgu.geo.wei.test;

import cn.edu.ctgu.geo.type.LatLonHeight;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

/**
 * 北斗网格经纬度范围计算器（从网格码反推范围）
 */
public class BeidouGridRangeCalculator2D {
    // 存储各层级的范围解析器（对应文档中1-10级编码逻辑的逆运算）
    private static final Map<Integer, Function<GridInfo, GridInfo>> RANGE_PARSERS = new HashMap<>();

    // 初始化各层级解析器（静态代码块，仅加载一次）
    static {
        RANGE_PARSERS.put(1, BeidouGridRangeCalculator2D::parseLevel1Range);   // 1级解析
        RANGE_PARSERS.put(2, BeidouGridRangeCalculator2D::parseLevel2Range);   // 2级解析
        RANGE_PARSERS.put(3, BeidouGridRangeCalculator2D::parseLevel3Range);   // 3级解析
        RANGE_PARSERS.put(4, BeidouGridRangeCalculator2D::parseLevel4Range);   // 4级解析
        RANGE_PARSERS.put(5, BeidouGridRangeCalculator2D::parseLevel5Range);   // 5级解析
        RANGE_PARSERS.put(6, BeidouGridRangeCalculator2D::parseLevel6Range);   // 6级解析
        RANGE_PARSERS.put(7, BeidouGridRangeCalculator2D::parseLevel7Range);   // 7级解析
        RANGE_PARSERS.put(8, BeidouGridRangeCalculator2D::parseLevel8Range);   // 8级解析
        RANGE_PARSERS.put(9, BeidouGridRangeCalculator2D::parseLevel9Range);   // 9级解析
        RANGE_PARSERS.put(10, BeidouGridRangeCalculator2D::parseLevel10Range); // 10级解析
    }

    // ------------------------------ 各层级范围解析逻辑（核心）------------------------------

    /**
     * 1级网格范围解析（格式：N/S + 2位经度列号 + 1位纬度行号，如N50J）
     * 规则：经度6°/级（01-60），纬度4°/级（A-V），范围：[-180°,180°]×[-88°,88°]
     */
    private static GridInfo parseLevel1Range(GridInfo gridInfo) {
        // 1级网格码长度固定为4（如N50J）  这里需要逐级分析，所以需要逐级截取
        String gridCode = gridInfo.getGridCode().substring(0, 4);

        // 解析1级码元：第1位=半球（N/S），第2-3位=经度列号（01-60），第4位=纬度行号（A-V）

        char hemisphere = gridCode.charAt(0);
        int lonColumn = Integer.parseInt(gridCode.substring(1, 3)); // 经度列号（01-60）
        char latRowChar = gridCode.charAt(3);                      // 纬度行号字符（A-V）
        int latRow = latRowChar - 'A' + 1;                        // 字符转数字（A=1，B=2...V=22）

        // 校验合法性
        if (lonColumn < 1 || lonColumn > 60) {
            throw new BeidouGridException("1级经度列号错误（01-60）：" + lonColumn);
        }
        if (latRow < 1 || latRow > 22) {
            throw new BeidouGridException("1级纬度行号错误（A-V）：" + latRowChar);
        }

        // 计算1级网格左下角基准经纬度（秒）
        BigDecimal lonStep = gridInfo.getCurrentLonStep(); // 1级经度步长=21600秒（6°）
        BigDecimal latStep = gridInfo.getCurrentLatStep(); // 1级纬度步长=14400秒（4°）

        // 经度基准：列号-1 × 步长 - 180°（将范围从[0°,360°]转为[-180°,180°]）
        BigDecimal baseLon = new BigDecimal(lonColumn - 1)
                .multiply(lonStep)
                .subtract(GridInfo.SECONDS_PER_DEGREE.multiply(new BigDecimal("180")));
        // 纬度基准：行号-1 × 步长，结合半球（N=正，S=负）
        BigDecimal baseLat = new BigDecimal(latRow - 1)
                .multiply(latStep)
                .multiply(hemisphere == 'N' ? BigDecimal.ONE : BigDecimal.valueOf(-1));

        // 更新网格信息
        return gridInfo.setCurrentLon(baseLon)
                .setCurrentLat(baseLat)
                .setColumn(lonColumn)
                .setRow(latRow);
    }

    /**
     * 2级网格范围解析（在1级基础上追加2位码元，如N50J47）
     * 规则：1级拆分为12×8个网格（经度30'/级，纬度30'/级），码元：第5位（0-B）=经度列，第6位（0-7）=纬度行
     */
    private static GridInfo parseLevel2Range(GridInfo gridInfo) {
        String gridCode = gridInfo.getGridCode().substring(0, 6);
       /* if (gridCode.length() != 6) {
            throw new BeidouGridException("2级网格码格式错误（需6位，如N50J47）：" + gridCode);
        }*/

        // 解析2级码元：第5位=经度列（0-B，12个），第6位=纬度行（0-7，8个）
        char lonColChar = gridCode.charAt(4);
        char latRowChar = gridCode.charAt(5);
        int lonColumn = charToNumber(lonColChar); // 0-B转0-11
        int latRow = charToNumber(latRowChar);    // 0-7转0-7

        // 校验合法性
        if (lonColumn < 0 || lonColumn > 11) {
            throw new BeidouGridException("2级经度列号错误（0-B）：" + lonColChar);
        }
        if (latRow < 0 || latRow > 7) {
            throw new BeidouGridException("2级纬度行号错误（0-7）：" + latRowChar);
        }

        // 计算2级基准：基于1级基准 + 列/行号 × 2级步长（结合经度正负方向）
        BigDecimal parentBaseLon = gridInfo.getCurrentLon(); // 1级左下角经度
        BigDecimal parentBaseLat = gridInfo.getCurrentLat(); // 1级左下角纬度
        BigDecimal lonStep = gridInfo.getCurrentLonStep();   // 2级经度步长=1800秒（30'）
        BigDecimal latStep = gridInfo.getCurrentLatStep();   // 2级纬度步长=1800秒（30'）

        // 经度方向：根据父级经度正负确定偏移方向（西经为负，东经为正）
        int lonDir = parentBaseLon.compareTo(BigDecimal.ZERO) >= 0 ? 1 : -1;
        BigDecimal baseLon = parentBaseLon.add(new BigDecimal(lonColumn * lonDir).multiply(lonStep));
        // 纬度方向：根据父级纬度正负确定偏移方向（南纬为负，北纬为正）
        int latDir = parentBaseLat.compareTo(BigDecimal.ZERO) >= 0 ? 1 : -1;
        BigDecimal baseLat = parentBaseLat.add(new BigDecimal(latRow * latDir).multiply(latStep));

        // 更新网格信息
        return gridInfo.setCurrentLon(baseLon)
                .setCurrentLat(baseLat)
                .setColumn(lonColumn)
                .setRow(latRow);
    }

    /**
     * 3级网格范围解析（在2级基础上追加1位码元，如N50J475）
     * 规则：2级拆分为2×3个网格（Z序编码），码元：0-5（对应Z序矩阵），经度15'/级，纬度10'/级
     */
    private static GridInfo parseLevel3Range(GridInfo gridInfo) {
        String gridCode = gridInfo.getGridCode().substring(0, 7);
       /* if (gridCode.length() != 7) {
            throw new BeidouGridException("3级网格码格式错误（需7位，如N50J475）：" + gridCode);
        }*/

        // 解析3级码元：第7位=Z序编码（0-5）
        int zCode = Integer.parseInt(gridCode.substring(6, 7));
        // Z序矩阵（对应文档图4）：行=经度方向，列=纬度方向
        int[][] zOrderMatrix = {{0, 2, 4}, {1, 3, 5}};
        int lonColumn = -1, latRow = -1;

        // 从Z序码反推行列号
        for (int i = 0; i < zOrderMatrix.length; i++) {
            for (int j = 0; j < zOrderMatrix[i].length; j++) {
                if (zOrderMatrix[i][j] == zCode) {
                    lonColumn = i; // 经度列（0-1）
                    latRow = j;    // 纬度行（0-2）
                    break;
                }
            }
        }
        if (lonColumn == -1 || latRow == -1) {
            throw new BeidouGridException("3级Z序码错误（0-5）：" + zCode);
        }

        // 计算3级基准：基于2级基准 + 行列号 × 3级步长
        BigDecimal parentBaseLon = gridInfo.getCurrentLon();
        BigDecimal parentBaseLat = gridInfo.getCurrentLat();
        BigDecimal lonStep = gridInfo.getCurrentLonStep(); // 3级经度步长=900秒（15'）
        BigDecimal latStep = gridInfo.getCurrentLatStep(); // 3级纬度步长=600秒（10'）

        int lonDir = parentBaseLon.compareTo(BigDecimal.ZERO) >= 0 ? 1 : -1;
        BigDecimal baseLon = parentBaseLon.add(new BigDecimal(lonColumn * lonDir).multiply(lonStep));
        int latDir = parentBaseLat.compareTo(BigDecimal.ZERO) >= 0 ? 1 : -1;
        BigDecimal baseLat = parentBaseLat.add(new BigDecimal(latRow * latDir).multiply(latStep));

        return gridInfo.setCurrentLon(baseLon)
                .setCurrentLat(baseLat)
                .setColumn(lonColumn)
                .setRow(latRow);
    }

    /**
     * 4级网格范围解析（在3级基础上追加2位码元，如N50J47549）
     * 规则：3级拆分为15×10个网格，码元：第8位（0-E）=经度列，第9位（0-9）=纬度行，经度1'/级，纬度1'/级
     */
    private static GridInfo parseLevel4Range(GridInfo gridInfo) {
        return parseCommonLevelRange(gridInfo, 9,
                "0123456789ABCDE".toCharArray(), // 经度列字符集（0-E=0-14）
                "0123456789".toCharArray(),      // 纬度行字符集（0-9=0-9）
                true); // 行列号从0开始（无需+1）

    }

    /**
     * 5级网格范围解析（在4级基础上追加2位码元，如N50J475493E）
     * 规则：4级拆分为15×15个网格，码元：第10-11位（0-E），经度4秒/级，纬度4秒/级
     */
    private static GridInfo parseLevel5Range(GridInfo gridInfo) {
        return parseCommonLevelRange(gridInfo, 11,
                "0123456789ABCDE".toCharArray(), // 经度列（0-E=0-14）
                "0123456789ABCDE".toCharArray(), // 纬度行（0-E=0-14）
                true);
    }

    /**
     * 6级网格范围解析（在5级基础上追加1位码元，如N50J475493E1）
     * 规则：5级拆分为2×2个网格（Z序编码），码元：0-3，经度2秒/级，纬度2秒/级
     */
    private static GridInfo parseLevel6Range(GridInfo gridInfo) {
        String gridCode = gridInfo.getGridCode().substring(0, 12);
       /* if (gridCode.length() != 12) {
            throw new BeidouGridException("6级网格码格式错误（需12位，如N50J475493E1）：" + gridCode);
        }*/

        int zCode = Integer.parseInt(gridCode.substring(11, 12));
        int[][] zOrderMatrix = {{0, 2}, {1, 3}}; // 文档图7的Z序矩阵
        int lonColumn = -1, latRow = -1;

        for (int i = 0; i < zOrderMatrix.length; i++) {
            for (int j = 0; j < zOrderMatrix[i].length; j++) {
                if (zOrderMatrix[i][j] == zCode) {
                    lonColumn = i;
                    latRow = j;
                    break;
                }
            }
        }
        if (lonColumn == -1 || latRow == -1) {
            throw new BeidouGridException("6级Z序码错误（0-3）：" + zCode);
        }

        // 计算基准（同3级逻辑）
        BigDecimal parentBaseLon = gridInfo.getCurrentLon();
        BigDecimal parentBaseLat = gridInfo.getCurrentLat();
        BigDecimal lonStep = gridInfo.getCurrentLonStep(); // 6级经度步长=2秒
        BigDecimal latStep = gridInfo.getCurrentLatStep(); // 6级纬度步长=2秒

        int lonDir = parentBaseLon.compareTo(BigDecimal.ZERO) >= 0 ? 1 : -1;
        BigDecimal baseLon = parentBaseLon.add(new BigDecimal(lonColumn * lonDir).multiply(lonStep));
        int latDir = parentBaseLat.compareTo(BigDecimal.ZERO) >= 0 ? 1 : -1;
        BigDecimal baseLat = parentBaseLat.add(new BigDecimal(latRow * latDir).multiply(latStep));

        return gridInfo.setCurrentLon(baseLon)
                .setCurrentLat(baseLat)
                .setColumn(lonColumn)
                .setRow(latRow);
    }

    /**
     * 7-10级网格范围解析（通用逻辑，均为8×8拆分，2位码元，0-7编码）
     * 7级：0.25秒/级；8级：1/32秒/级；9级：1/256秒/级；10级：1/2048秒/级
     */
    private static GridInfo parseLevel7Range(GridInfo gridInfo) {
        return parseCommonLevelRange(gridInfo, 14,
                "01234567".toCharArray(), // 经度列（0-7）
                "01234567".toCharArray(), // 纬度行（0-7）
                false); // 行列号从1开始（需-1转0）
    }

    private static GridInfo parseLevel8Range(GridInfo gridInfo) {
        return parseCommonLevelRange(gridInfo, 16,
                "01234567".toCharArray(),
                "01234567".toCharArray(),
                false);
    }

    private static GridInfo parseLevel9Range(GridInfo gridInfo) {
        return parseCommonLevelRange(gridInfo, 18,
                "01234567".toCharArray(),
                "01234567".toCharArray(),
                false);
    }

    private static GridInfo parseLevel10Range(GridInfo gridInfo) {
        return parseCommonLevelRange(gridInfo, 20,
                "01234567".toCharArray(),
                "01234567".toCharArray(),
                false);
    }

    // ------------------------------ 通用工具方法 ------------------------------

    /**
     * 通用层级范围解析（适用于4-5级、7-10级，非Z序编码的层级）
     *
     * @param gridInfo     网格信息
     * @param expectLength 该层级网格码的预期长度
     * @param lonChars     经度列字符集
     * @param latChars     纬度行字符集
     * @param isZeroBased  是否0基行列号（true=0开始，false=1开始）
     */
    private static GridInfo parseCommonLevelRange(GridInfo gridInfo, int expectLength,
                                                  char[] lonChars, char[] latChars,
                                                  boolean isZeroBased) {
        //对应网格层级长度不一样，需截取
        String gridCode = gridInfo.getGridCode().substring(0, expectLength);
       /* if (gridCode.length() != expectLength) {
            throw new BeidouGridException(
                    String.format("%d级网格码格式错误（需%d位）：%s",
                            gridInfo.getGridStepLevel(), expectLength, gridCode));
        }*/

        // 解析当前层级的2位码元（经度列+纬度行）
        int codeStartIndex = expectLength - 2;
        char lonColChar = gridCode.charAt(codeStartIndex);
        char latRowChar = gridCode.charAt(codeStartIndex + 1);

        // 字符转行列号（通过字符集匹配）
        int lonColumn = getCharIndex(lonColChar, lonChars);
        int latRow = getCharIndex(latRowChar, latChars);

        // 若为1基行列号，转为0基（用于计算偏移）
        if (!isZeroBased) {
            lonColumn--;
            latRow--;
        }

        // 计算当前层级基准经纬度
        BigDecimal parentBaseLon = gridInfo.getCurrentLon();
        BigDecimal parentBaseLat = gridInfo.getCurrentLat();
        BigDecimal lonStep = gridInfo.getCurrentLonStep();
        BigDecimal latStep = gridInfo.getCurrentLatStep();

        int lonDir = parentBaseLon.compareTo(BigDecimal.ZERO) >= 0 ? 1 : -1;
        BigDecimal baseLon = parentBaseLon.add(new BigDecimal(lonColumn * lonDir).multiply(lonStep));
        int latDir = parentBaseLat.compareTo(BigDecimal.ZERO) >= 0 ? 1 : -1;
        BigDecimal baseLat = parentBaseLat.add(new BigDecimal(latRow * latDir).multiply(latStep));

        return gridInfo.setCurrentLon(baseLon)
                .setCurrentLat(baseLat)
                .setColumn(lonColumn)
                .setRow(latRow);
    }

    /**
     * 字符转数字（0-9→0-9，A-B→10-11，E→14等）
     */
    private static int charToNumber(char c) {
        if (c >= '0' && c <= '9') {
            return c - '0';
        } else if (c >= 'A' && c <= 'Z') {
            return 10 + (c - 'A');
        }
        throw new BeidouGridException("无效网格码字符：" + c);
    }

    /**
     * 在字符集中查找字符的索引（如在"0123456789ABCDE"中找'E'→14）
     */
    private static int getCharIndex(char c, char[] chars) {
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] == c) {
                return i;
            }
        }
        throw new BeidouGridException("字符" + c + "不在字符集内");
    }

    // ------------------------------ 对外暴露方法 ------------------------------

    /**
     * 计算指定网格码的经纬度范围（入口方法）
     *
     * @param gridCode 北斗网格码（如N50J475493E100040407）
     * @param level    网格层级（1-10，需与网格码长度匹配）
     * @return 范围数组：[minLon(度), maxLon(度), minLat(度), maxLat(度)]
     */
    public static LatLonHeight calculateGridRange2D(String gridCode, int level) {
        // 1. 校验层级与网格码长度匹配（参考文档中层级-长度对应关系）
        Map<Integer, Integer> levelLengthMap = new HashMap<>();
        levelLengthMap.put(1, 4);    // 1级：4位（如N50J）
        levelLengthMap.put(2, 6);    // 2级：6位（如N50J47）
        levelLengthMap.put(3, 7);    // 3级：7位（如N50J475）
        levelLengthMap.put(4, 9);    // 4级：9位（如N50J47549）
        levelLengthMap.put(5, 11);   // 5级：11位（如N50J475493E）
        levelLengthMap.put(6, 12);   // 6级：12位（如N50J475493E1）
        levelLengthMap.put(7, 14);   // 7级：15位（如N50J475493E100）
        levelLengthMap.put(8, 16);   // 8级：19位（如N50J475493E10004）
        levelLengthMap.put(9, 18);   // 9级：21位（如N50J475493E1000404）
        levelLengthMap.put(10, 20);  // 10级：23位（如N50J475493E100040407）

        Integer expectLength = levelLengthMap.get(level);
        if (expectLength == null || gridCode.length() != expectLength) {
            throw new BeidouGridException(
                    String.format("%d级网格码需%d位，当前为%d位：%s",
                            level, expectLength, gridCode.length(), gridCode));
        }

        // 2. 初始化网格信息
        GridInfo gridInfo = GridInfo.builder()
                .gridCode(gridCode)
                .gridStepLevel(level)
                .column(0).row(0).build();


        // 3. 按层级递进解析（从1级到目标层级）
        for (int i = 1; i <= level; i++) {
            BigDecimal parentBaseLon = gridInfo.getCurrentLon(); // 1级左下角经度
            BigDecimal parentBaseLat = gridInfo.getCurrentLat(); // 1级左下角纬度

            Function<GridInfo, GridInfo> parser = RANGE_PARSERS.get(i);
            if (parser == null) {
                throw new BeidouGridException("不支持的层级：" + level);
            }
            // 临时更新当前解析的层级（用于获取对应步长）
            gridInfo.setGridStepLevel(i);
            //临时更行上个基准经纬度
            gridInfo.setCurrentLon(parentBaseLon);
            gridInfo.setCurrentLat(parentBaseLat);
            gridInfo = parser.apply(gridInfo);
        }

        // 4. 计算最终范围（秒转度，基准+步长=最大值）
        BigDecimal minLonSec = gridInfo.getCurrentLon();
        BigDecimal maxLonSec = minLonSec.add(gridInfo.getCurrentLonStep());
        BigDecimal minLatSec = gridInfo.getCurrentLat();
        BigDecimal maxLatSec = minLatSec.add(gridInfo.getCurrentLatStep());

        // 转换为十进制度（保留8位小数，确保精度）
        double minLon = GridInfo.secondsToDegree(minLonSec).doubleValue();
        double maxLon = GridInfo.secondsToDegree(maxLonSec).doubleValue();
        double minLat = GridInfo.secondsToDegree(minLatSec).doubleValue();
        double maxLat = GridInfo.secondsToDegree(maxLatSec).doubleValue();

        return new LatLonHeight(minLon, maxLon, minLat, maxLat, 0.0);
    }

    // ------------------------------ 测试方法 ------------------------------
    public static void main(String[] args) {
        String code1 = "N50J47539A81";
        LatLonHeight latLonHeight = calculateGridRange2D(code1, 6);
        System.out.printf("=== 层级%d：%s ===\n", 6, code1);
        System.out.printf("经度范围：%.8f ~ %.8f °\n", latLonHeight.getMinLongitude(), latLonHeight.getMaxLongitude());
        System.out.printf("纬度范围：%.8f ~ %.8f °\n", latLonHeight.getMinLatitude(),latLonHeight.getMaxLatitude() );
        System.out.println("经度范围（度分秒）：" + lonToDms(latLonHeight.getMinLongitude()) + " ~ " + lonToDms(latLonHeight.getMaxLongitude()));
        System.out.println("纬度范围（度分秒）：" + latToDms(latLonHeight.getMinLatitude()) + " ~ " + latToDms (latLonHeight.getMaxLatitude()));
        test(latLonHeight.getMinLongitude(), latLonHeight.getMaxLongitude(), latLonHeight.getMinLatitude(),latLonHeight.getMaxLatitude());
        // 测试文档中的10级网格码（level:10:N50J475493E100040407）
       /* String[] testCodes = {
                "N50J",          // level 1
                "N50J47",        // level 2
                "N50J475",       // level 3
                "N50J47539",     // level 4
                "N50J47539B8",   // level 5
                "N50J47539B80",  // level 6
                "N50J47539B8043", // level 7
                "N50J47539B804364", // level 8
                "N50J47539B80436432", // level 9
                "N50J47539B8043643213" // level 10
        };


        for (int i = 0; i < testCodes.length; i++) {
            int level = i + 1;
            String code = testCodes[i];
            try {
                double[] range = calculateGridRange2D(code, level);
                System.out.printf("=== 层级%d：%s ===\n", level, code);
                System.out.printf("经度范围：%.8f ~ %.8f °\n", range[0], range[1]);
                System.out.printf("纬度范围：%.8f ~ %.8f °\n", range[2], range[3]);
                System.out.println("经度范围（度分秒）：" + lonToDms(range[0]) + " ~ " + lonToDms(range[1]));
                System.out.println("纬度范围（度分秒）：" + latToDms(range[2]) + " ~ " + latToDms(range[3]));
                test(range[0], range[1],range[2], range[3]);
            } catch (Exception e) {
                System.err.printf("层级%d解析失败：%s\n", level, e.getMessage());
            }
        }*/
    }

    /**
     * 测试：根据生成北斗网格码，计算出经纬度范围的实际跨度
     * @param minLon  最小经度
     * @param maxLon  最大经度
     * @param minLat  最小纬度
     * @param maxLat  最大纬度
     */
    private static void test(double minLon,double maxLon,double minLat,double maxLat ){

        // 1. 计算跨度
        double lonSpan = maxLon - minLon;
        double latSpan = maxLat - minLat;

        // 2. 计算纬度方向长度（米）
        double latDistance = latSpan * 111320; // 111320米/°

        // 3. 计算经度方向长度（米）：需乘当前纬度的cos值
        double midLat = (minLat + maxLat) / 2;
        double cosMidLat = Math.cos(Math.toRadians(midLat)); // 角度转弧度后算cos
        double lonDistance = lonSpan * 111320 * cosMidLat;

        // 4. 输出结果
        System.out.printf("经度跨度：%.8f°，实际长度：%.2f 米%n", lonSpan, lonDistance);
        System.out.printf("纬度跨度：%.8f°，实际长度：%.2f 米%n", latSpan, latDistance);
        System.out.printf("范围面积：%.2f 平方米%n\n", lonDistance * latDistance);
    }


    /**
     * 十进制经度转度分秒
     * @param lon  十进制经度
     * @return  eg：东经E50.00000000
     */
    public static String lonToDms(double lon) {
        //格式化秒为8位小数，匹配原始数据精度
        DecimalFormat SEC_FORMAT = new DecimalFormat("0.00000000");
        int deg = (int) lon;
        double rem = lon - deg;
        int min = (int) (rem * 60);
        double sec = (rem * 60 - min) * 60;
        return String.format("%d°%d′%s″E", deg, min, SEC_FORMAT.format(sec));
    }

    /**
     * 十进制纬度转度分秒
     * @param lat  十进制纬度
     * @return  eg：北纬N50.00000000
     */
    public static String latToDms(double lat) {
        //格式化秒为8位小数，匹配原始数据精度
        DecimalFormat SEC_FORMAT = new DecimalFormat("0.00000000");
        int deg = (int) lat;
        double rem = lat - deg;
        int min = (int) (rem * 60);
        double sec = (rem * 60 - min) * 60;
        return String.format("%d°%d′%s″N", deg, min, SEC_FORMAT.format(sec));
    }

}